package com.cl.short_video_java.aspect;

import ch.qos.logback.core.util.TimeUtil;

import com.cl.short_video_java.annotation.NoRepeatSubmit;
import com.cl.short_video_java.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.support.RequestContext;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * @Author 付
 * @Date 2024-03-03 14:23
 * @Version 1.0
 * @description
 * @since 1.0
 */
@Aspect
@Component
@Slf4j
public class RepeatSubmitAspect {
	@Resource
	RedissonClient redissonClient;

	// 切点，对注解@NoRepeatSubmit进行切面
	@Pointcut("@annotation(noRepeatSubmit)")
	public void pointCut(NoRepeatSubmit noRepeatSubmit) {
	}

	// 环绕通知，在方法执行前操作，执行后操作
	@Around("pointCut(noRepeatSubmit)")
	public Object around(ProceedingJoinPoint point, NoRepeatSubmit noRepeatSubmit) throws Throwable {
		// 这里不能直接获取request，需要转型获取
		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = requestAttributes.getRequest();
		String token = request.getHeader("token");
		String path = request.getServletPath();
		String key = token + path;

		// 获取锁
		RLock lock = redissonClient.getLock(key);
		/**
		 * 上锁
		 *  waitTime 上锁时间，这里是 0 ，意味着当请求时立即上锁
		 *  time 锁持续时间，这里时获取注解里面的方法设置的时间，当时间到了，锁释放
		 *  timeUnit 时间单位，这里时秒级别
		 */
		boolean tryLock = lock.tryLock(0, noRepeatSubmit.lockTime(), TimeUnit.SECONDS);

		if (tryLock) {
			// 上锁成功，执行切点方法
			return point.proceed();
		} else {
			return Result.error("操作太频繁了哦！");
		}
	}

}
